Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feat] 댓글 기능 구현 #232

Open
wants to merge 25 commits into
base: develop
Choose a base branch
from

Conversation

zbqmgldjfh
Copy link
Member

@zbqmgldjfh zbqmgldjfh commented Feb 18, 2025

TODO (진행중)

  • 공지에 댓글 추가 기능
    • 기존의 토큰이 아닌 이메일로 로그인 한 사용자만 댓글 작성 가능하도록
  • 댓글에 대댓글 추가 기능 (depth 2까지만)
  • 댓글 편집
  • 공지목록 조회시 댓글 수 함께 조회해서 반환하는 기능
  • 공지 단건 클릭시 공지 상세 페이지로 넘어가면서 호출할 댓글 목록 조회 api 구현
    • 대댓글도 같이 조회되도록
  • 댓글 삭제

추가로, 로그인이 어떻게 될지 몰라서? 일단 TOKEN으로 로그인 한다 생각하고 처리하였습니다.
로그인 구현이 완료되면 해당 부분 알맞게 변경해주세요~

Copy link

github-actions bot commented Feb 18, 2025

Unit Test Results

  53 files    53 suites   56s ⏱️
273 tests 272 ✔️ 1 💤 0
276 runs  275 ✔️ 1 💤 0

Results for commit 929a1d2.

♻️ This comment has been updated with latest results.

@zbqmgldjfh zbqmgldjfh force-pushed the feat/add-comment-to-notice-#230 branch from d1d6cc6 to b66dea7 Compare February 20, 2025 12:29
Copy link
Collaborator

@rlagkswn00 rlagkswn00 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

커서 페이지네이션을 이렇게도 구현할수 있구나라는 생각에 무릎을 탁 치고 갑니닷!!!!

몇개 궁금한거 있어서 코멘트 남겼는데 확인해주심 감사하겠슴다🫡

Comment on lines 76 to 78
if (isNotCommentOwner(findComment, findUser, findNotice)) {
throw new NotFoundException(ErrorCode.COMMENT_NOT_FOUND);
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NOT_FOUND 보다는 403에러를 반환하는 에러코드(Ex. NO_PERMISSIONCOMMENT_ACCESS_DENIED과같은..?)를 추가로 만드는게 더 의미를 잘 표현할 수 있지 않을가 생각합니닷


import java.util.Objects;

@Slf4j
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

활용되지 않는 어노테이션인거 같아유

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

앗... 로그 남긴다는게 까먹었네요.... 수신~

Comment on lines +34 to +36
private final NoticeCommentWritingUseCase noticeCommentWritingUseCase;
private final NoticeCommentEditingUseCase noticeCommentEditingUseCase;
private final NoticeCommentDeletingUseCase noticeCommentDeletingUseCase;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

하나의 CommandUseCase로 묶지 않고 Create, Update, Delete를 구분한 이유가 궁금함니닷
(가독성과 관리가 편해서인가 싶은 생각이 들었슴니당)

Copy link
Member Author

@zbqmgldjfh zbqmgldjfh Feb 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

사실 CommandUseCase 는 너무 뭉둥그려진 유스케이스에 해당합니다. 거의 모든 유스케이스를 CommandUseCase 와 QueryUseCase로 이분법적으로 나눌 수 있을탠데... 이러면 인터페이스의 명세라는 의미가 사실 조금 사라진다 생각합니다.

가급적 유스케이스도 분리하여 의미를 전달해주는 것 이 좋아요, 다만 그럼 이전에는 왜? CommandUseCase 로 했냐? 라고 물어본다면, 그건 그당시 기존 레이어드 아키텍처에서 헥사고날로 전환하면서... 작업량이 많아... 일단 하나로 퉁쳤습니다...

언젠가 기존의 유스케이스도 명확하게 분리해야지라고 생각 중입나다~

Comment on lines +41 to +53
public ResponseEntity<BaseResponse> createComment(
@Parameter(description = "공지 ID") @PathVariable("id") Long id,
@RequestHeader(USER_TOKEN_HEADER_KEY) String userToken,
@RequestBody NoticeCommentCreateRequest request
) {
if (request.parentId() == null) {
var command = new WriteCommentCommand(
userToken,
id,
request.content()
);

noticeCommentWritingUseCase.process(command);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

var가 자바에도 있다는건 알고 있었는데 실제로 보니 상당히 코틀린같으면서도 자바같은 요 느낌....ㅋㅋㅋㅎㅎㅋㅋㅎ

이걸 보니 값을 객체로 변환하는 과정에서만큼은 굳이 변수 선언부에 객체이름을 다 적지 않아도 충분하다는 것을 느끼게 되네유

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ㅋㅋㅋ 사실 맘같아서는 코틀린 쓰고 싶은데... 그다음 서버 학생분 물려드릴거 생각하여... 자바로 유지중...

*/
CursorBasedList<CommentAndSubCommentsResult> findComments(Long noticeId, String cursor, int size);

record ReadCommentsCommand(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

혹시 이건 언제쓰는 커맨드인가유??

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ㅋㅋㅋㅋ 만들고 사용을 안했군요... 확인 감사합니다~

Comment on lines 75 to 114
public CursorBasedList<CommentAndSubCommentsResult> findComments(Long noticeId, String cursor, int size) {
return CursorBasedList.of(
Math.min(size, MAX_COMMENT_QUERY_SIZE),
it -> it.comment().id().toString(),
searchSize -> {
List<CommentReadModel> parentComments = commentQueryPort
.findExcludeSubCommentByCursor(noticeId, cursor, searchSize);

Set<Long> parentCommentIds = parentComments.stream()
.map(CommentReadModel::getId)
.collect(Collectors.toSet());

List<CommentReadModel> subComments = commentQueryPort.findSubCommentByIds(noticeId, parentCommentIds);

// 부모 댓글을 Key로 하고, 그에 해당하는 자식 댓글 리스트를 값으로 가지는 Map 생성
Map<Long, List<CommentDetailResponse>> parentToSubCommentsMap = subComments.stream()
.filter(subComment -> subComment.getParentId() != null)
.map(CommentDetailResponse::of)
.collect(Collectors.groupingBy(CommentDetailResponse::parentId));

// 부모 댓글과 자식 댓글을 조합하여 CommentAndSubCommentsResult 리스트 생성
List<CommentAndSubCommentsResult> commentResults = parentComments.stream()
.map(parent -> {
List<CommentDetailResponse> subCommentList = parentToSubCommentsMap
.getOrDefault(parent.getId(), Collections.emptyList());

// 부모 댓글이 삭제되었고, 답글이 없는 경우 제외
if (parent.getDestroyedAt() != null && subCommentList.isEmpty()) {
return null;
}

return new CommentAndSubCommentsResult(CommentDetailResponse.of(parent), subCommentList);
})
.filter(Objects::nonNull)
.toList();

return commentResults.subList(START_INDEX, Math.min(searchSize, commentResults.size()));
}
);
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WoW🤩

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

연산량이 많은 부분이라 메서드로 추출 안했습니다~
그냥 하나의 findComments() 안에서 다 보는것이 좋을것 같아서요~

Comment on lines 3 to 13
public class Cursor {

private final String stringCursor;

public Cursor(String stringCursor) {
this.stringCursor = stringCursor;
}

public String getStringCursor() {
return stringCursor;
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

혹시 이 커서 객체는 어디에 쓰는건가유??

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ㅋㅋㅋㅋ 이것도... 만들고 사용을 안했군요... 확인 감사합니다~
원래 Controller에서 받을때 한번 감싸서 전달했어야 해요~

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants